/* * 
 * Copyright © 2008 HNA Co. Ltd. 
 * All right reserved. 
 */

package com.gamutsoft.amb.common.util;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;

import com.gamutsoft.amb.common.bean.CondictionsBean;
import com.gamutsoft.amb.common.constants.Constants;

/**
 * <h3>Class name</h3> 多条件查询工具 <h4>Description</h4>
 * 
 * <h4>Special Notes</h4>
 * 
 * 
 * @ver 0.1
 * @author Jay.Wu 2008-9-11
 * 
 */
public class QueryUtil {
	private List<CondictionsBean> condictions;
	private CondictionsBean condictionsBean;
	private PageUtil pageUtil;
	private String select;
	private String hideCondiction;
	private String orderBy;
	private String conRelation;
	private String groupBy;

	public QueryUtil() {
		condictionsBean = new CondictionsBean();
		condictions = new ArrayList<CondictionsBean>();
	}

	/**
	 * 快速增加bean，完整
	 * 
	 * @param property
	 * @param value
	 * @param condiction
	 * @param startStr
	 * @param endStr
	 * @return
	 */
	public CondictionsBean add(String property, Object value,
			String condiction, String startStr, String endStr) {
		CondictionsBean bean = new CondictionsBean();
		bean.setProperty(property);
		bean.setValue(value);
		bean.setCondiction(condiction);
		bean.setStartStr(startStr);
		bean.setEndStr(endStr);
		condictions.add(bean);
		return bean;
	}

	/**
	 * 快速增加bean，完整
	 * 
	 * @param property
	 * @param value
	 * @param condiction
	 * @param startStr
	 * @param endStr
	 * @return
	 */
	public CondictionsBean addOr(String property, Object value,
			String condiction, String startStr, String endStr) {
		CondictionsBean bean = new CondictionsBean();
		bean.setProperty(property);
		bean.setValue(value);
		bean.setCondiction(condiction);
		bean.setStartStr(startStr);
		bean.setEndStr(endStr);
		bean.setRelation(Constants.RELATION_OR);
		condictions.add(bean);
		return bean;
	}

	/**
	 * 快速增加bean，完整
	 * 
	 * @param property
	 * @param value
	 * @param anotherValue
	 * @param startStr
	 * @param endStr
	 * @return
	 */
	public CondictionsBean addBetween(String property, Object value,
			Object anotherValue, String startStr, String endStr) {
		CondictionsBean bean = new CondictionsBean();
		bean.setProperty(property);
		bean.setValue(value);
		bean.setAnotherValue(anotherValue);
		bean.setCondiction("between");
		bean.setStartStr(startStr);
		bean.setEndStr(endStr);
		condictions.add(bean);
		return bean;
	}

	/**
	 * 快速增加bean，完整
	 * 
	 * @param property
	 * @param value
	 * @param anotherProperty
	 * @param anotherValue
	 * @param startStr
	 * @param endStr
	 * @return
	 */
	public CondictionsBean addOrBetween(String property, Object value,
			Object anotherValue, String startStr, String endStr) {
		CondictionsBean bean = new CondictionsBean();
		bean.setProperty(property);
		bean.setValue(value);
		bean.setAnotherValue(anotherValue);
		bean.setCondiction("between");
		bean.setStartStr(startStr);
		bean.setEndStr(endStr);
		bean.setRelation(Constants.RELATION_OR);
		condictions.add(bean);
		return bean;
	}

	/**
	 * 快速增加bean，中等
	 * 
	 * @param property
	 * @param value
	 * @param condiction
	 * @return
	 */
	public CondictionsBean add(String property, Object value, String condiction) {
		return add(property, value, condiction, condictionsBean.getStartStr(),
				condictionsBean.getEndStr());
	}

	/**
	 * 快速增加bean，中等
	 * 
	 * @param property
	 * @param value
	 * @param condiction
	 * @return
	 */
	public CondictionsBean addOr(String property, Object value,
			String condiction) {
		return addOr(property, value, condiction,
				condictionsBean.getStartStr(), condictionsBean.getEndStr());
	}

	/**
	 * 快速增加bean，精简
	 * 
	 * @param property
	 * @param value
	 * @return
	 */
	public CondictionsBean add(String property, Object value) {
		return add(property, value, condictionsBean.getCondiction());
	}

	/**
	 * 快速增加bean，精简
	 * 
	 * @param property
	 * @param value
	 * @param anotherValue
	 * @return
	 */
	public CondictionsBean addBetween(String property, Object value,
			Object anotherValue) {
		return addBetween(property, value, anotherValue,
				condictionsBean.getStartStr(), condictionsBean.getEndStr());
	}

	/**
	 * 快速增加bean，精简
	 * 
	 * @param property
	 * @param value
	 * @param anotherValue
	 * @return
	 */
	public CondictionsBean addOrBetween(String property, Object value,
			Object anotherValue) {
		return addOrBetween(property, value, anotherValue,
				condictionsBean.getStartStr(), condictionsBean.getEndStr());
	}

	/**
	 * 快速增加bean，精简
	 * 
	 * @param property
	 * @param value
	 * @return
	 */
	public CondictionsBean addOr(String property, Object value) {
		return addOr(property, value, condictionsBean.getCondiction());
	}

	public List<CondictionsBean> add(CondictionsBean bean) {
		condictions.add(bean);
		return condictions;
	}

	/**
	 * /** 创建查询bean 1. 判断条件：=、like、bet等。<br>
	 * 2.类型：int、float、date等，不写默认为String。 <br>
	 * 3.括号内的为字段名称，括号是必须的。 <br>
	 * 4. 如： <code>=_int(property)</code>，其中=为查询条件，int为属性类型，property为字段名称 <br>
	 * <code>bet_date(abc)_start<br>bet_date(abc)_end</code>
	 * 
	 * @param request
	 * @param propertys
	 *            允许查询的字段
	 * @author Jay.Wu
	 */

	@SuppressWarnings("unchecked")
	public static QueryUtil createConditions(HttpServletRequest request,
			String[] propertys) throws Exception {
		QueryUtil queryUtil = new QueryUtil();
		Map<String, String[]> parameterMap = request.getParameterMap();
		// Map<String, String> parameterMap = request.getParameterMap();
		if (parameterMap != null && parameterMap.size() > 0) {

			for (String key : parameterMap.keySet()) {
				int lBrackets = key.indexOf('(');
				int rBrackets = key.indexOf(')');
				String property = key.substring(lBrackets + 1, rBrackets);

				String value = request.getParameter(key);
				if (StringUtils.isBlank(property)
						|| StringUtils.isBlank(value)
						|| isPropertyExist(queryUtil.getCondictions(), property)
						|| !isAllowProperty(propertys, property)) {
					continue;
				}

				String anotherValue = request.getParameter("bet_date("
						+ property + ")_end");

				if (StringUtils.isNotBlank(anotherValue)) {
					value = request.getParameter("bet_date(" + property
							+ ")_start");
					queryUtil.add(createCondition(key, value, anotherValue));
				} else {
					queryUtil.add(createCondition(key, value, null));
				}
			}
		}

		return queryUtil;
	}

	/**
	 * 判断是否已经添加过该属性
	 * 
	 * @param list
	 * @param property
	 * @return
	 */
	private static boolean isPropertyExist(List<CondictionsBean> list,
			String property) {
		for (CondictionsBean bean : list) {
			if (bean.getProperty().equals(property)) {
				return true;
			}
		}

		return false;
	}

	/**
	 * 是否允许查询该属性
	 * 
	 * @param propertys
	 * @param property
	 * @return
	 */
	private static boolean isAllowProperty(String[] propertys, String property) {
		if (propertys == null) {
			return true;
		}

		for (String allowProperty : propertys) {
			if (allowProperty.equals(property)) {
				return true;
			}
		}

		return false;
	}

	/**
	 * 创建查询bean 1. 判断条件：=、like、bet等。<br>
	 * 2.类型：int、float、date等，不写默认为String。 <br>
	 * 3.括号内的为字段名称，括号是必须的。 <br>
	 * 4. 如： <code>=_int(property)</code>，其中=为查询条件，int为属性类型，property为字段名称 <br>
	 * <code>bet_date(abc)_start<br>bet_date(abc)_end</code>
	 * 
	 * @param name
	 * @param value
	 * @param anotherValue
	 * @author Jay.Wu
	 */
	public static CondictionsBean createCondition(String name, String value,
			String anotherValue) throws Exception {
		// 初始化条件
		Map<String, String> conditions = new HashMap<String, String>();
		conditions.put("=", "=");
		conditions.put(">", ">");
		conditions.put(">=", ">=");
		conditions.put("<", "<");
		conditions.put("<=", "<=");
		conditions.put("bet", "between");
		conditions.put("like", "like");

		boolean hasCondition = false;
		String conditionValue = null;

		// 检查是否有查询条件
		for (String key : conditions.keySet()) {

			if (name.startsWith(key)) {
				hasCondition = true;
				String condition = conditions.get(key);
				conditionValue = condition;
				break;
			}
		}

		if (!hasCondition) {
			return null;
		}

		int lBrackets = name.indexOf('(');
		int rBrackets = name.indexOf(')');
		int underline = name.indexOf('_');

		String type = null;
		// 若为-1，则默认为String
		if (underline != -1) {
			type = name.substring(underline + 1, lBrackets);
		}
		String property = name.substring(lBrackets + 1, rBrackets);

		CondictionsBean bean = new CondictionsBean();
		bean.setCondiction(conditionValue);
		bean.setProperty(property);
		bean.setValue(createObjectByValue(type, value));
		bean.setAnotherValue(createObjectByValue(type, anotherValue));

		return bean;
	}

	public static void main(String[] args) throws Exception {
		// QueryUtil queryUtil = new QueryUtil();
		System.out
				.println(QueryUtil.createCondition("=_int(abc)", "123", null));
		System.out.println(QueryUtil.createCondition("like(abc)", "123", null));
		System.out.println(QueryUtil.createCondition("bet_date(abc)_start",
				"1985-03-14", "2008-09-01"));
	}

	/**
	 * 根据字段的类型，自动新建对象
	 * 
	 * @param typeClass
	 * @param value
	 * @return
	 * @throws Exception
	 */
	public static Object createObjectByValue(Class<?> typeClass, Object value)
			throws Exception {
		if (value == null) {
			return null;
		}

		if (Date.class.equals(typeClass)) {
			return DateUtil.parse(value.toString(), "yyyy-MM-dd");
		} else {
			Constructor<?> con = typeClass
					.getConstructor(new Class[] { String.class });
			value = con.newInstance(new Object[] { value });
		}

		return value;
	}

	/**
	 * 根据类型，自动新建对象
	 * 
	 * @param typeClass
	 * @param value
	 * @return
	 * @throws Exception
	 */
	public static Object createObjectByValue(String type, Object value)
			throws Exception {
		if (value == null) {
			return null;
		}

		type = getJavaType(type);

		if (Date.class.getName().equals(type)) {
			return DateUtil.parse(value.toString(), "yyyy-MM-dd");
		} else {
			Class<?> myClass = Class.forName(type);
			Constructor<?> con = myClass
					.getConstructor(new Class[] { String.class });
			value = con.newInstance(new Object[] { value });
		}

		return value;
	}

	/**
	 * 注意此类型要写到配置文件中去
	 * 
	 * @param type
	 * @return
	 */
	private static String getJavaType(String type) {
		Map<String, String> types = new HashMap<String, String>();
		types.put("DEFAULT", "java.lang.String");
		types.put("int", "java.lang.Integer");
		types.put("float", "java.lang.Float");
		types.put("double", "java.lang.Double");
		types.put("date", "java.util.Date");
		return types.get(type);
	}

	/**
	 * @return the condictions
	 */
	public List<CondictionsBean> getCondictions() {
		return condictions;
	}

	/**
	 * @param condictions
	 *            the condictions to set
	 */
	public void setCondictions(List<CondictionsBean> condictions) {
		this.condictions = condictions;
	}

	/**
	 * @return the condictionsBean
	 */
	public CondictionsBean getCondictionsBean() {
		return condictionsBean;
	}

	/**
	 * @param condictionsBean
	 *            the condictionsBean to set
	 */
	public void setCondictionsBean(CondictionsBean condictionsBean) {
		this.condictionsBean = condictionsBean;
	}

	/**
	 * @return the pageUtil
	 */
	public PageUtil getPageUtil() {
		return pageUtil;
	}

	/**
	 * @param pageUtil
	 *            the pageUtil to set
	 */
	public void setPageUtil(PageUtil pageUtil) {
		this.pageUtil = pageUtil;
	}

	/**
	 * @return the select
	 */
	public String getSelect() {
		return select;
	}

	/**
	 * @param select
	 *            the select to set
	 */
	public void setSelect(String select) {
		this.select = select;
	}

	/**
	 * @return the hideCondiction
	 */
	public String getHideCondiction() {
		return hideCondiction;
	}

	/**
	 * @param hideCondiction
	 *            the hideCondiction to set
	 */
	public void setHideCondiction(String hideCondiction) {
		this.hideCondiction = hideCondiction;
	}

	/**
	 * @return the conRelation
	 */
	public String getConRelation() {
		return conRelation;
	}

	/**
	 * @param conRelation
	 *            the conRelation to set
	 */
	public void setConRelation(String conRelation) {
		this.conRelation = conRelation;
	}

	/**
	 * @return the groupBy
	 */
	public String getGroupBy() {
		return groupBy;
	}

	/**
	 * @param groupBy
	 *            the groupBy to set
	 */
	public void setGroupBy(String groupBy) {
		this.groupBy = groupBy;
	}

	public String getOrderBy() {
		return orderBy;
	}

	public void setOrderBy(String orderBy) {
		this.orderBy = orderBy;
	}
}
